package com.dj.mingkong.portal.boot.handler;


import cn.hutool.core.exceptions.ExceptionUtil;
import com.dj.mingkong.common.exception.BaseRuntimeException;
import com.dj.mingkong.common.infrastructure.base.dto.rest.RestResponse;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.nio.file.AccessDeniedException;
import java.util.List;

/**
 * 全局异常处理器
 *
 * @author luokangtao
 * @create 2019-07-15 2:06
 * @ControllerAdvice是controller的一个辅助类，最常用的就是作为全局异常处理的切面类
 */
@RestControllerAdvice
@Slf4j
public class BaseExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public RestResponse<Boolean> error(Exception e) {
        String message = ExceptionUtil.getMessage(e);
        log.error("异常信息message:{}", message);
        String lineString = ExceptionUtil.stacktraceToOneLineString(e);
        log.error("异常信息stacktraceToOneLineString:{}", lineString);
        return StringUtils.isNotBlank(lineString) ? RestResponse.build500(lineString)
                : RestResponse.build500();
    }

   /* @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public RestResponse<Boolean> methodArgumentNotValidException(Exception e) {
        String message = ExceptionUtil.getMessage(e);
        log.info("异常信息message:{}", message);
        String lineString = ExceptionUtil.stacktraceToOneLineString(e);
        log.info("异常信息stacktraceToOneLineString:{}", lineString);
        //处理校验信息
        int mess = message.lastIndexOf("default message");
        int length = "default message".length();
        String substring = message.substring(mess + length, message.length() - 2);
        return RestResponse.error("500", substring);
    }*/

    /**
     * {@code @RequestBody} 参数校验不通过时抛出的异常处理
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public RestResponse<Boolean> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        /*StringBuilder sb = new StringBuilder("校验失败:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getField()).append("：").append(fieldError.getDefaultMessage());
        }
        String msg = sb.toString();
        if (StringUtils.isNotBlank(msg)) {
            return RestResponse.error("500", msg);
        }
        return RestResponse.error("500", "校验异常");*/
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        if (CollectionUtils.isNotEmpty(allErrors)) {
            ObjectError error = allErrors.get(0);
            String msg = String.format("%s，校验不通过，%s", error.getObjectName(), error.getDefaultMessage());
            log.error("MethodArgumentNotValidException:{}", msg);
            return RestResponse.build400(error.getDefaultMessage());
        }
        return RestResponse.build400();
    }

    /**
     * {@code @PathVariable} 和 {@code @RequestParam} 参数校验不通过时抛出的异常处理
     */
 /*   @ExceptionHandler({ConstraintViolationException.class})
    public RestResponse<Boolean> handleConstraintViolationException(ConstraintViolationException ex) {
        if (StringUtils.isNotBlank(ex.getMessage())) {
            return RestResponse.error("500", ex.getMessage());
        }
        return RestResponse.error("500", "校验异常");
    }*/
    @ExceptionHandler(value = BaseRuntimeException.class)
    public RestResponse<Boolean> baseException(Exception e) {
        String message = ExceptionUtil.getMessage(e);
        log.error("自定义异常信息message:{}", message);
        String lineString = ExceptionUtil.stacktraceToOneLineString(e);
        log.error("自定义异常信息stacktraceToOneLineString:{}", lineString);
        if (StringUtils.isNotBlank(((BaseRuntimeException) e).getCode())) {
            return RestResponse.error(((BaseRuntimeException) e).getCode(), e.getMessage());
        }
        return RestResponse.build400(e.getMessage());
    }

    @ExceptionHandler(value = ExpiredJwtException.class)
    public RestResponse<Boolean> expiredJwtException(Exception e) {
        String lineString = ExceptionUtil.stacktraceToOneLineString(e);
        log.error("异常信息stacktraceToOneLineString:{}", lineString);
        return StringUtils.isNotBlank(lineString) ? RestResponse.build401(lineString)
                : RestResponse.build401();
    }


    /**
     * 参数绑定异常统一处理，拦截 BindException 异常
     */
    /*@ExceptionHandler(value = {BindException.class})
    public RestResponse<Boolean> handleValidException(BindException e) {
        String message = ExceptionUtil.getMessage(e);
        log.info("异常信息message:{}", message);
        String lineString = ExceptionUtil.stacktraceToOneLineString(e);
        log.info("异常信息stacktraceToOneLineString:{}", lineString);
        //处理校验信息
        int mess = message.lastIndexOf("default message");
        int length = "default message".length();
        String substring = message.substring(mess + length, message.length() - 2);
        return RestResponse.error("500", substring);
    }*/
    @ExceptionHandler({BindException.class})
    public RestResponse<Boolean> validationBodyException(BindException exception) {
        BindingResult result = exception.getBindingResult();
        List<ObjectError> errors = result.getAllErrors();
        errors.forEach(p -> {
            FieldError fieldError = (FieldError) p;
            log.error("参数校验出错 : object: {},field: {},errorMessage: {}", fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
        });
        List<String> errList = errors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).toList();
        return RestResponse.build400(String.join(",", errList));
    }

    /**
     * 约束校验异常统一处理
     */
    @ExceptionHandler(value = {ConstraintViolationException.class})
    public RestResponse<Boolean> handleValidException(ConstraintViolationException e) {
        log.error("数据校验异常，{}，异常类型：{}", e.getMessage(), e.getClass());
        List<String> violations = e.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage).toList();
        String error = violations.get(0);
        return StringUtils.isNotBlank(error) ? RestResponse.build500(error)
                : RestResponse.build500();
    }

    /**
     * 未知异常处理
     */
    @ExceptionHandler(value = Throwable.class)
    public RestResponse<Boolean> handleException(Throwable t) {
        log.error("未知异常，{}，异常类型：{}", t.getMessage(), t.getClass());
        return RestResponse.build500("未知异常");
    }

    /**
     * 参数格式异常处理
     */
    @ExceptionHandler({IllegalArgumentException.class})
    public RestResponse<String> badRequestException(IllegalArgumentException ex) {
        log.error("参数格式不合法：{}", ex.getMessage());
        return RestResponse.build400("参数格式不符！");
    }

    /**
     * 权限不足异常处理
     */
    @ExceptionHandler({AccessDeniedException.class})
    public RestResponse<String> badRequestException(AccessDeniedException ex) {
        log.error("权限不足异常: {}", ex.getMessage());
        return RestResponse.build403();
    }

    /**
     * 参数缺失异常处理
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public RestResponse<String> badRequestException(Exception ex) {
        log.error("参数缺失异常: {}", ex.getMessage());
        return RestResponse.build400("缺少必填参数！");
    }

    /**
     * 空指针异常
     */
    @ExceptionHandler(NullPointerException.class)
    //@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public RestResponse<String> handleTypeMismatchException(NullPointerException ex) {
        log.error("空指针异常，{}", ex.getMessage());
        return RestResponse.build500("空指针异常");
    }

}
